package client

import (
	"errors"
	. "fastdp-ops/pkg/common/model"
	. "fastdp-ops/pkg/server/api/middleware"
	"fmt"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"os"
	"path"
	"strings"
	"time"
)

// PlayCmd 执行yaml编排任务的命令
var PlayCmd = &cobra.Command{
	Use:   "play",
	Short: "执行YAML定义的编排任务流程",
	Long: `执行YAML格式定义的运维任务流程。
任务流程可以包含在多个主机上执行的不同模块操作。

示例YAML文件结构:
name: 部署k8s集群
version: v1.32.0
config_file: config.yaml
stages:
  - stage: 初始化环境
    role: k8s_cluster
    tasks: init
`,
	Example: `
  # 执行指定的YAML任务文件
  fastdp-ops play -f deploy-app.yaml

  # 执行任务并显示详细日志
  fastdp-ops play -f deploy-app.yaml -v

  # 仅检查任务文件语法，不实际执行
  fastdp-ops play -f deploy-app.yaml --dry-run

  # 列出所有阶段
  fastdp-ops play -f deploy-app.yaml -l

  # 从指定阶段开始执行
  fastdp-ops play -f deploy-app.yaml -s "准备环境"
`,
	Args: cobra.NoArgs, // 不接受位置参数
	PreRunE: func(cmd *cobra.Command, args []string) error {
		// 获取文件路径参数
		file, _ := cmd.Flags().GetString("file")
		if file == "" {
			return errors.New("必须使用 -f/--file 指定要执行的YAML文件")
		}

		// 检查文件是否存在
		if _, err := os.Stat(file); os.IsNotExist(err) {
			return fmt.Errorf("指定的文件不存在: %s", file)
		}

		// 检查文件扩展名是否为yaml或yml
		ext := strings.ToLower(path.Ext(file))
		if ext != ".yaml" && ext != ".yml" {
			return fmt.Errorf("文件必须是YAML格式（.yaml或.yml），当前文件: %s", file)
		}

		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		InitZapLogger()
		defer Logger.Sync()

		// 初始化数据库
		SqlLiteInit()
		// 获取命令行参数
		file, _ := cmd.Flags().GetString("file")
		stageFlag, _ := cmd.Flags().GetString("stage")
		list, _ := cmd.Flags().GetBool("list")
		verbose, _ := cmd.Flags().GetBool("verbose")
		dryRun, _ := cmd.Flags().GetBool("dry-run")

		// 打印执行信息
		if verbose {
			fmt.Printf("开始处理任务文件: %s\n", file)
		}

		// 解析文件路径
		fileExt := path.Ext(file)
		fileName := path.Base(file)
		dir := path.Dir(file)

		// 初始化viper
		v := viper.New()
		v.SetConfigName(strings.TrimSuffix(fileName, fileExt))
		v.SetConfigType(strings.TrimPrefix(fileExt, "."))
		v.AddConfigPath(dir)

		// 读取配置文件
		if err := v.ReadInConfig(); err != nil {
			fmt.Printf("❌ 读取配置文件失败: %v\n", err)
			os.Exit(1)
		}

		// 解析到结构体
		var playbook Playbook
		if err := v.Unmarshal(&playbook); err != nil {
			fmt.Printf("❌ 解析YAML文件失败: %v\n", err)
			os.Exit(1)
		}
		if list {
			fmt.Printf("\n📋 任务: %s（版本: %s）\n", playbook.Name, playbook.Version)
			fmt.Println("📋 所有阶段列表:")
			for i, stage := range playbook.Stages {
				fmt.Printf("  %d. %s\n", i+1, stage.Stage)
				fmt.Printf("    角色：%s\n", stage.Role)
			}
			return
		}

		// 验证playbook基本信息
		if playbook.Name == "" {
			fmt.Println("⚠️ 警告: YAML文件中未指定任务名称")
		}
		if playbook.Version == "" {
			playbook.Version = "未知版本"
		}
		var configFile string
		if playbook.ConfigFile == "" {
			configFile = path.Join(dir, "config.yaml")
		} else if path.IsAbs(playbook.ConfigFile) {
			configFile = playbook.ConfigFile
		} else {
			configFile = path.Join(dir, playbook.ConfigFile)
		}
		// 检查配置文件是否存在
		if _, err := os.Stat(configFile); os.IsNotExist(err) {
			fmt.Printf("❌ 配置文件不存在: %s", configFile)
			os.Exit(1)
		}
		v, err := ParserConfig(configFile)
		if err != nil {
			fmt.Printf("❌ 配置解析失败: %w", err)
		}
		machineRoles, err := GetMachineRole(v) // 改造 GetMachineRole 接受 Viper 实例
		if err != nil {
			fmt.Printf("❌ 读取角色配置失败: %w", err)
		}
		globalConfig, err := GetGlobalConfig(v)
		if err != nil {
			fmt.Printf("⚠️ 全局配置为空（非致命错误）: %v\n", err)   // 全局配置为空可警告但不终止
			globalConfig = make(map[string]interface{}) // 确保返回非 nil map
		}

		startIndex := 0
		if stageFlag != "" {
			found := false
			for i, stage := range playbook.Stages {
				if stage.Stage == stageFlag {
					startIndex = i
					found = true
					break
				}
			}
			if !found {
				fmt.Printf("❌ 指定的阶段 '%s' 不存在\n", stageFlag)
				fmt.Println("可用的阶段列表:")
				for i, stage := range playbook.Stages {
					fmt.Printf("  %d. %s\n", i+1, stage.Stage)
				}
				os.Exit(1)
			}
			fmt.Printf("🚀 将从阶段 '%s' 开始执行 (阶段 %d/%d)\n",
				stageFlag, startIndex+1, len(playbook.Stages))
		}
		// 初始化执行统计
		var (
			totalStages     = len(playbook.Stages)
			successStages   = 0
			failedStages    = 0
			lastFailedStage string
		)
		// 打印任务概览
		fmt.Printf("\n📋 任务概览: %s（版本: %s）\n", playbook.Name, playbook.Version)
		fmt.Printf("📊 总阶段数: %d | 开始执行时间: %s\n", totalStages, time.Now().Format("15:04:05"))
		if dryRun {
			fmt.Println("⚠️ 模拟执行模式：不会实际执行任务，仅展示流程")
			return // 若为dry-run，解析完成后退出
		}
		fmt.Println("\n🚀 开始执行任务流程...")
		stagesToExecute := playbook.Stages[startIndex:]
		// 显示阶段和任务详情
		for i, stage := range stagesToExecute {
			stageIdx := i + 1 // 阶段序号从1开始
			fmt.Printf("\n===== 阶段 %d/%d: %s =====\n", stageIdx, totalStages, stage.Stage)
			fmt.Printf("开始执行时间: %s\n", time.Now().Format("15:04:05"))

			// 执行阶段（捕获错误）
			if err := PlayStage(stage, verbose, machineRoles, globalConfig, dir); err != nil {
				// 阶段执行失败
				failedStages++
				lastFailedStage = stage.Stage
				fmt.Printf("❌ 阶段 %d/%d 执行失败: %v\n", stageIdx, totalStages, err)
				break
			}

			// 阶段执行成功
			successStages++
			fmt.Printf("✅ 阶段 %d/%d 执行成功\n", stageIdx, totalStages)
			fmt.Printf("执行结束时间: %s\n", time.Now().Format("15:04:05"))
		}
		// 输出最终执行结果（汇总统计）
		fmt.Printf("\n📝 任务执行总结: %s\n", playbook.Name)
		fmt.Printf("总阶段数: %d | 成功: %d | 失败: %d\n", totalStages, successStages, failedStages)
		if failedStages > 0 {
			fmt.Printf("❌ 任务执行失败（最后失败阶段：%s）\n", lastFailedStage)
			os.Exit(1)
		} else {
			fmt.Printf("✅ 所有阶段执行成功 | 结束时间: %s\n", time.Now().Format("15:04:05"))
		}
	},
}

func init() {
	// 注册命令行参数
	PlayCmd.Flags().StringP("file", "f", "", "指定要执行的YAML任务文件（必需）")
	PlayCmd.Flags().BoolP("verbose", "v", false, "显示详细的执行过程")
	PlayCmd.Flags().Bool("dry-run", false, "仅检查任务文件语法，不实际执行")
	PlayCmd.Flags().StringP("stage", "s", "", "从指定stage开始执行")
	PlayCmd.Flags().BoolP("list", "l", false, "列出所有阶段")

	// 标记文件参数为必需
	if err := PlayCmd.MarkFlagRequired("file"); err != nil {
		fmt.Printf("初始化命令参数失败: %v\n", err)
	}

}
